package main.java.person.fjsp.algorithm.ts.utils;

import main.java.person.fjsp.algorithm.ts.entity.DisjunctiveGraph;
import main.java.person.fjsp.algorithm.ts.entity.DisjunctiveGraphNode;
import main.java.person.fjsp.common.entity.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 工具类
 * @author xcy
 */
public class TSUtils {
    Random random = new Random();

    /**
     * 根据插入信息，将v插入机器中
     * @param insertInformation 插入信息，第一个元素为移除的关键节点的number，第二个元素为关键节点选择的机器k，第三个元素为在机器中选择的位置
     * @return 插入完毕的析取图
     */
    public DisjunctiveGraph kInsertion(DisjunctiveGraph graph, DataManager dataManager, int[] insertInformation) {

        List<DisjunctiveGraphNode> nodes = graph.getNodes();
        int vNumber=insertInformation[0];
        DisjunctiveGraphNode v = nodes.get(vNumber);
        int k=insertInformation[1];
        int insertIndex=insertInformation[2];
        int jobPreV=insertInformation[3];
        int jobNextV=insertInformation[4];
        List<Integer> qk = graph.getMachineAndNodeListMap().get(k);
        List<Integer> vMachineSeq =  graph.getMachineAndNodeListMap().get(v.getMachineNum());
        int vIndexInMachine = searchRemoveNodeInMachine(0, vMachineSeq.size() - 1, vMachineSeq, v.getNumber(), nodes);

        //在插入之前，需要先将v移除原本的机器
        if (vIndexInMachine != 0) {
            int machinePreV = vMachineSeq.get(vIndexInMachine - 1);
//            System.out.println("机器紧前工序移除前："+nodes.get(machinePreV));
            if (machinePreV != jobPreV) {
                if (!nodes.get(machinePreV).getNextNodes().removeIf(nextNode -> nextNode == v.getNumber())) {
                    throw new IllegalStateException("not expecting to arrive here");
                }
                if (!v.getPreNodes().removeIf(preNode -> preNode == nodes.get(machinePreV).getNumber())) {
                    throw new IllegalStateException("not expecting to arrive here");
                }
            }
//            System.out.println("机器紧前工序移除后："+nodes.get(machinePreV));
        }
        if (vIndexInMachine != vMachineSeq.size() - 1) {
            int machineNextV = vMachineSeq.get(vIndexInMachine + 1);
//            System.out.println("机器紧后工序移除前："+nodes.get(machineNextV));
            if (machineNextV != jobNextV) {
                if (!nodes.get(machineNextV).getPreNodes().removeIf(preNode -> preNode == v.getNumber())) {
                    throw new IllegalStateException("not expecting to arrive here");
                }
                if (!v.getNextNodes().removeIf(nextNode -> nextNode == nodes.get(machineNextV).getNumber())) {
                    throw new IllegalStateException("not expecting to arrive here");
                }
            }
//            System.out.println("机器紧后工序移除后："+nodes.get(machineNextV));
        }
        if (vIndexInMachine != 0 && vIndexInMachine != vMachineSeq.size() - 1) {
            DisjunctiveGraphNode machinePreV = nodes.get(vMachineSeq.get(vIndexInMachine - 1));
            DisjunctiveGraphNode machineNextV = nodes.get(vMachineSeq.get(vIndexInMachine + 1));
            if (machinePreV.getJobNum() != machineNextV.getJobNum() || machinePreV.getNumber() + 1 != machineNextV.getNumber()) {
                machinePreV.getNextNodes().add(machineNextV.getNumber());
                machineNextV.getPreNodes().add(machinePreV.getNumber());
            }
        }
        vMachineSeq.remove(vIndexInMachine);

        //将v插入k中选中的位置，断开insertIndex前后工序的机器弧，并重连v与机器紧前/紧后工序（若有且不是作业紧前紧后工序）机器弧，并重新设置机器、权重
        //断开
        qk.add(insertIndex, v.getNumber());
        if (insertIndex !=0&&insertIndex !=qk.size()-1) {
            DisjunctiveGraphNode machinePreNode = nodes.get(qk.get(insertIndex - 1));
            DisjunctiveGraphNode machineNextNode = nodes.get(qk.get(insertIndex + 1));
            if (machinePreNode.getJobNum() != machineNextNode.getJobNum() || machinePreNode.getNumber() + 1 != machineNextNode.getNumber()) {
                //不是相邻的同作业工序，断开它们之间的连接弧
                if (!machinePreNode.getNextNodes().removeIf(nextNode -> nodes.get(nextNode).getNumber() == machineNextNode.getNumber())) {
                    throw new IllegalStateException("not expecting to arrive here");
                }
                if (!machineNextNode.getPreNodes().removeIf(preNode -> nodes.get(preNode).getNumber() == machinePreNode.getNumber())) {
                    throw new IllegalStateException("not expecting to arrive here");
                }
            }
        }
        //重连
        if (insertIndex !=0) {
            //前一个工序存在，如果前一个工序跟当前工序不是相邻的同作业工序，进行连接
            DisjunctiveGraphNode machinePreNode = nodes.get(qk.get(insertIndex - 1));
            if (machinePreNode.getJobNum() != v.getJobNum() || machinePreNode.getNumber() + 1 != v.getNumber()) {
                machinePreNode.getNextNodes().add(v.getNumber());
                v.getPreNodes().add(machinePreNode.getNumber());
            }
        }
        if (insertIndex !=qk.size()-1) {
            //后一个工序存在，如果后一个工序跟当前工序不是相邻的同作业工序，进行连接
            DisjunctiveGraphNode machineNextNode = nodes.get(qk.get(insertIndex + 1));
            if (machineNextNode.getJobNum() != v.getJobNum() || machineNextNode.getNumber() - 1 != v.getNumber()) {
                machineNextNode.getPreNodes().add(v.getNumber());
                v.getNextNodes().add(machineNextNode.getNumber());
            }
        }
        v.setMachineNum(k);
        Integer newProcessTime = dataManager.getOperationProcessTimeMap().get(v.getOperationCode() + "-" + k);
        v.setProcessTime(newProcessTime);
        nodes.forEach(node->{
            node.setLatestPreNode(null);
            node.setStartTime(0);
            node.setTailTime(0);
        });
        //重新计算所有节点的头长度 尾长度、关键路径
        calStartTime(nodes.get(0), nodes, new boolean[nodes.size()], false);
        calTailTime(nodes.get(nodes.size() - 1), nodes, new boolean[nodes.size()], false);
        List<Integer> newCriticalPath = new ArrayList<>();
        getCriticalPath(nodes.get(nodes.size() - 1), nodes, newCriticalPath);
        graph.setInsertInfo(insertInformation);
        graph.setCriticalPath(newCriticalPath);
        graph.setMakespan(nodes.get(nodes.size() - 1).getStartTime());
//        nodes.forEach(System.out::println);
//        System.out.println(graph.getMakespan());
        return graph;
    }


    /**
     * 在析取图的关键路径上随机选择一个节点，将其从机器中移除，选择另一个机器k，选择一个位置插入
     * @return 数组，第一个元素为移除的关键节点的number，第二个元素为关键节点选择的机器k，第三个元素为在机器中选择的位置
     */
    public int[] getInsertInfo(DisjunctiveGraph graph, DataManager dataManager){

        List<DisjunctiveGraphNode> nodes = graph.getNodes();
        Map<Integer, List<Integer>> jobMap = graph.getJobAndNodeListMap();

        //随机选择关键路径上的一个节点
        int randomIndex = random.nextInt(graph.getCriticalPath().size());
        DisjunctiveGraphNode v = nodes.get(graph.getCriticalPath().get(randomIndex));
        List<Integer> vJobSeq = jobMap.get(v.getJobNum());
        int vIndexInJob = searchRemoveNodeInJob(0, vJobSeq.size() - 1, vJobSeq, v.getNumber());
        int jobPreV = vIndexInJob == 0 ? nodes.get(0).getNumber() : vJobSeq.get(vIndexInJob - 1);
        int jobNextV = vIndexInJob == vJobSeq.size() - 1 ? nodes.get(nodes.size() - 1).getNumber() : vJobSeq.get(vIndexInJob + 1);
        //工序v在子图中的头长度和尾长度此时为作业紧前工序的头长度+作业紧前工序处理时间，作业紧后工作的尾长度+作业紧后工序处理时间
        int vStartTime = nodes.get(jobPreV).getStartTime() + nodes.get(jobPreV).getProcessTime();
        int vTailTime = nodes.get(jobNextV).getTailTime() + nodes.get(jobNextV).getProcessTime();
        //重新为v随机选择一个机器k
        List<Integer> vOptionalMachines = dataManager.getOperationCodeAndMachineListMap().get(v.getOperationCode());
        Integer k = vOptionalMachines.get(random.nextInt(vOptionalMachines.size()));
        List<Integer> qk = new ArrayList<>(graph.getMachineAndNodeListMap().get(k));
        //v刚好选中了原来的机器，qk中要除去v
        qk.removeIf(nodeNumber->nodeNumber==v.getNumber());
        //用二分查找获得v在k中可插入的范围lk和rk
        int leftIndex = 0, rightIndex = qk.size();
        if (!qk.isEmpty() && vTailTime < nodes.get(qk.get(0)).getTailTime() + nodes.get(qk.get(0)).getProcessTime()) {
            leftIndex = searchLk(0, qk.size() - 1, qk, vTailTime, nodes);
        }
        if (!qk.isEmpty() && vStartTime < nodes.get(qk.get(qk.size() - 1)).getStartTime() + nodes.get(qk.get(qk.size() - 1)).getProcessTime()) {
            rightIndex = searchRk(0, qk.size() - 1, qk, vStartTime, nodes);
        }
        //选择v在k中插入的位置
        int insertIndex;
        if (rightIndex < leftIndex) {
            //此时lk和rk有交集，可插入的位置为[rightIndex,leftIndex]
            insertIndex = random.nextInt(leftIndex - rightIndex + 1) + rightIndex;
        } else {
            //此时lk和rk无交集，可插入的位置为[leftIndex,rightIndex]
            insertIndex = random.nextInt(rightIndex - leftIndex + 1) + leftIndex;
        }
        return new int[]{v.getNumber(),k,insertIndex,jobPreV,jobNextV};
    }

    /**
     * 在qk中寻找Lk最后一个工序的索引
     *
     * @return lk最后一个工序索引+1
     */
    private int searchLk(int start, int end, List<Integer> qk, int vTailTime, List<DisjunctiveGraphNode> nodes) {
        if (start == end) {
            int xTailTime = nodes.get(qk.get(start)).getTailTime();
            int xProcessTime = nodes.get(qk.get(start)).getProcessTime();
            if (vTailTime == xTailTime + xProcessTime) {
                //如果找到，lk的要求是tx+px>tv，所以lk最后一道工序的索引是start-1
                return start;
            } else {
                //如果没有找到，当前索引是target最近的左边，刚好是lk的最后一道工序
                return start + 1;
            }
        }
        int middle = (int) Math.ceil((start + end) / 2.0);
        if (vTailTime <= nodes.get(qk.get(middle)).getTailTime() + nodes.get(qk.get(middle)).getProcessTime()) {
            return searchLk(middle, end, qk, vTailTime, nodes);
        } else {
            return searchLk(start, middle - 1, qk, vTailTime, nodes);
        }
    }

    /**
     * 在k中寻找Rk第一个工序的索引
     */
    private int searchRk(int start, int end, List<Integer> qk, int vStartTime, List<DisjunctiveGraphNode> nodes) {
        if (start == end) {
            int xStartTime = nodes.get(qk.get(start)).getStartTime();
            int xProcessTime = nodes.get(qk.get(start)).getProcessTime();
            if (vStartTime == xStartTime + xProcessTime) {
                //如果找到，此时sx+px=sv，但是Rk的第一道工序要求sx+px>sv，所以第一道工序的索引是start+1
                return start + 1;
            } else {
                //没有找到，此时找到的索引是target最近的右边，刚好是Rk的第一道工序
                return start;
            }
        }
        int middle = (start + end) / 2;
        if (nodes.get(qk.get(middle)).getStartTime() + nodes.get(qk.get(middle)).getProcessTime() >= vStartTime) {
            return searchRk(start, middle, qk, vStartTime, nodes);
        } else {
            return searchRk(middle + 1, end, qk, vStartTime, nodes);
        }
    }

    /**
     * 在vJobSeq中找到target的索引
     */
    private int searchRemoveNodeInJob(int start, int end, List<Integer> vJobSeq, int target) {
        if (start == end) {

            if (vJobSeq.get(start) == target) {
                return start;
            } else {
                throw new IllegalStateException("not expecting to arrive here");
            }
        }
        int middle = (start + end) / 2;
        if (vJobSeq.get(middle) >= target) {
            return searchRemoveNodeInJob(start, middle, vJobSeq, target);
        } else {
            return searchRemoveNodeInJob(middle + 1, end, vJobSeq, target);
        }
    }

    /**
     * 在vMachineSeq中找到target的索引
     */
    private int searchRemoveNodeInMachine(int start, int end, List<Integer> vMachineSeq, int target, List<DisjunctiveGraphNode> nodes) {
        if (start == end) {
            if (vMachineSeq.get(start) == target) {
                return start;
            } else {
                throw new IllegalStateException("not expecting to arrive here");
            }
        }
        int middle = (start + end) / 2;
        if (nodes.get(vMachineSeq.get(middle)).getStartTime() >= nodes.get(target).getStartTime()) {
            return searchRemoveNodeInMachine(start, middle, vMachineSeq, target, nodes);
        } else {
            return searchRemoveNodeInMachine(middle + 1, end, vMachineSeq, target, nodes);
        }
    }


    /**
     * 根据可行调度计划生成析取图（遗传算法的调度计划结果转化为析取图，以方便进行禁忌搜索）
     */
    public DisjunctiveGraph convertScheduleToGraph(ScheduleResult scheduleResult, DataManager dataManager) {
        List<DisjunctiveGraphNode> nodes = new ArrayList<>();
        //先根据作业优先顺序生成有向图
        ArrayList<Job> jobs = scheduleResult.getJobs();
        int nodeNumber = 0;
        DisjunctiveGraphNode endNode = new DisjunctiveGraphNode("end", dataManager.getOperationNum() + 1, new ArrayList<>(), new ArrayList<>());
        endNode.setMachineNum(-1);
        endNode.setJobNum(-1);
        for (int i = 0; i < jobs.size(); i++) {
            if (i == 0) {
                //加入虚拟开始节点
                DisjunctiveGraphNode startNode = new DisjunctiveGraphNode("start", nodeNumber, new ArrayList<>(), new ArrayList<>());
                startNode.setMachineNum(-1);
                startNode.setJobNum(-1);
                nodes.add(startNode);
                nodeNumber++;
            }
            Job job = jobs.get(i);
            for (int j = 0; j < job.getOperations().size(); j++) {
                Operation operation = job.getOperations().get(j);
                DisjunctiveGraphNode node = new DisjunctiveGraphNode(operation.getCode(), nodeNumber, new ArrayList<>(), new ArrayList<>());
                node.setJobNum(operation.getJobNumber());
                node.setMachineNum(operation.getMachineNum());
                node.setProcessTime(operation.getProcessTime());
                if (j == 0) {
                    //作业的第一道工序的前驱节点必定是虚拟开始节点
                    node.getPreNodes().add(nodes.get(0).getNumber());
                    nodes.get(0).getNextNodes().add(node.getNumber());
                } else {
                    DisjunctiveGraphNode preNode = nodes.get(nodes.size() - 1);
                    preNode.getNextNodes().add(node.getNumber());
                    node.getPreNodes().add(preNode.getNumber());
                }
                if (j == job.getOperations().size() - 1) {
                    //作业的最后一道工序必定连向虚拟结束节点
                    node.getNextNodes().add(endNode.getNumber());
                    endNode.getPreNodes().add(node.getNumber());
                }
                nodes.add(node);
                nodeNumber++;
            }
        }
        nodes.add(endNode);
        //接着加入机器的析取弧
        for (Machine machine : scheduleResult.getMachines()) {
            for (int i = 0; i < machine.getOperations().size() - 1; i++) {
                Operation operation = machine.getOperations().get(i);
                Operation nextOperation = machine.getOperations().get(i + 1);
                //得到当前工序和下一个工序对应的节点
                DisjunctiveGraphNode node = nodes.get(dataManager.getOperationCodeAndIndexMap().get(operation.getCode()) + 1);
                DisjunctiveGraphNode nextNode = nodes.get(dataManager.getOperationCodeAndIndexMap().get(nextOperation.getCode()) + 1);
                //当前工序和下一个工序属于同一个作业的前后工序，不用添加机器弧
                if (node.getJobNum() != nextNode.getJobNum() || node.getNumber() + 1 != nextNode.getNumber()) {
                    node.getNextNodes().add(nextNode.getNumber());
                    nextNode.getPreNodes().add(node.getNumber());
                }
            }
        }
        //计算每个节点的头长度和尾长度
        calStartTime(nodes.get(0), nodes, new boolean[nodes.size()], false);
        calTailTime(nodes.get(nodes.size() - 1), nodes, new boolean[nodes.size()], false);
        //获得关键路径
        List<Integer> criticalPath = new ArrayList<>();
        getCriticalPath(nodes.get(nodes.size() - 1), nodes, criticalPath);
        //按照机器号对节点进行分组，分组之后的机器序列需要按照升序排序
        Map<Integer, List<Integer>> machineMap = nodes.stream().collect(Collectors.groupingBy(DisjunctiveGraphNode::getMachineNum,
                Collectors.mapping(DisjunctiveGraphNode::getNumber, Collectors.toList())));
        //析取图中的节点的机器并不全面，可能会漏掉一些机器，需要手动补上
        for (int i = 0; i < dataManager.getMachineNum(); i++) {
            if (!machineMap.containsKey(i)) {
                machineMap.put(i, new ArrayList<>());
            }
        }
        Map<Integer, List<Integer>> jobMap = nodes.stream().collect(Collectors.groupingBy(DisjunctiveGraphNode::getJobNum,
                Collectors.mapping(DisjunctiveGraphNode::getNumber, Collectors.toList())));
        jobMap.forEach((key, value) -> value.sort(Integer::compareTo));
        machineMap.forEach((key, value) -> value.sort(Comparator.comparingInt(o -> nodes.get(o).getStartTime())));
        return new DisjunctiveGraph(nodes, machineMap, jobMap, criticalPath, nodes.get(nodes.size() - 1).getStartTime(),new int[]{0});
    }


    /**
     * 计算析取图中每一个节点的头长度
     *
     * @param node    虚拟开始节点
     * @param visited 记录节点被访问的情况
     * @param back    该节点是否是前驱节点
     */
    private void calStartTime(DisjunctiveGraphNode node, List<DisjunctiveGraphNode> nodes, boolean[] visited, boolean back) {
        if (visited[node.getNumber()]) {
            //该节点被访问过，返回
            return;
        }
        //访问所有未被访问过的前驱节点，并记录前驱节点之中的最迟完工时间
        for (Integer preNode : node.getPreNodes()) {
            if (!visited[preNode]) {
                calStartTime(nodes.get(preNode), nodes, visited, true);
            }
            int startTime = nodes.get(preNode).getStartTime() + nodes.get(preNode).getProcessTime();
            if (startTime >= node.getStartTime()) {
                node.setStartTime(startTime);
                node.setLatestPreNode(preNode);
            }
        }
        //所有前驱节点被访问完毕，标记该节点被访问过
        visited[node.getNumber()] = true;
        //如果此时是前驱节点的搜索过程，返回到原本的节点
        if (back) {
            return;
        }
        //访问该节点的所有未被访问过的后继节点
        for (Integer nextNode : node.getNextNodes()) {
            if (!visited[nextNode]) {
                calStartTime(nodes.get(nextNode), nodes, visited, false);
            }
        }
    }

    /**
     * 计算析取图中每一个节点的尾长度
     *
     * @param node    虚拟结束节点
     * @param visited 记录节点是否被访问过
     * @param forward 该节点是否是后继节点
     */
    private void calTailTime(DisjunctiveGraphNode node, List<DisjunctiveGraphNode> nodes, boolean[] visited, boolean forward) {
        if (visited[node.getNumber()]) {
            //该节点被访问过，返回
            return;
        }
        //访问所有未被访问过的后继节点，并记录后继节点之中的最大尾长度
        for (Integer nextNode : node.getNextNodes()) {
            if (!visited[nextNode]) {
                calTailTime(nodes.get(nextNode), nodes, visited, true);
            }
            node.setTailTime(Math.max(node.getTailTime(), nodes.get(nextNode).getTailTime() + nodes.get(nextNode).getProcessTime()));
        }
        //所有后继节点被访问完毕，标记该节点被访问过
        visited[node.getNumber()] = true;
        //如果此时是后继节点的搜索过程，返回到原本的节点
        if (forward) {
            return;
        }
        //访问该节点的所有未被访问过的前驱节点
        for (Integer preNode : node.getPreNodes()) {
            if (!visited[preNode]) {
                calTailTime(nodes.get(preNode), nodes, visited, false);
            }
        }
    }

    /**
     * 获得析取图的关键路径
     *
     * @param node         第一次输入需要是析取图的虚拟结束节点
     * @param criticalPath 传入一个空的列表，该方法执行完毕后列表会按开始时间为序填充关键节点
     */
    private void getCriticalPath(DisjunctiveGraphNode node, List<DisjunctiveGraphNode> nodes, List<Integer> criticalPath) {
        if (null == node.getLatestPreNode()) {
            //到达头节点，为了之后方便，开始节点不要添加入关键路径
            return;
        }
        //进入上一个节点
        getCriticalPath(nodes.get(node.getLatestPreNode()), nodes, criticalPath);
        if (!"end".equals(node.getOperationCode())) {
            //为了之后方便，结束节点不要添加入关键路径
            criticalPath.add(node.getNumber());
        }
    }


    /**
     * 验证生成的析取图是否正确
     *
     * @param disjunctiveGraph 析取图
     * @param machines         原调度计划
     */
    public void verify(DisjunctiveGraph disjunctiveGraph, List<Machine> machines, DataManager dataManager) {
        //验证节点数量与工序数量是否相符，以及节点所属机器是否与原调度计划相符
        int operationNum = 0;
        for (Machine machine : machines) {
            if (machine.getOperations().isEmpty()) {
                continue;
            }
            operationNum += machine.getOperations().size();
            Set<String> set = disjunctiveGraph.getMachineAndNodeListMap().get(machine.getNumber())
                    .stream()
                    .map(nodeIndex -> disjunctiveGraph.getNodes().get(nodeIndex).getOperationCode())
                    .collect(Collectors.toSet());
            for (Operation operation : machine.getOperations()) {
                if (!set.contains(operation.getCode())) {
                    throw new IllegalStateException("not expecting to arrive here");
                }
                //得到该工序对应的节点，查看头长度是否计算正确
                Integer index = dataManager.getOperationCodeAndIndexMap().get(operation.getCode());
                DisjunctiveGraphNode node = disjunctiveGraph.getNodes().get(index + 1);
                if (!node.getOperationCode().equals(operation.getCode())) {
                    throw new IllegalStateException("not expecting to arrive here");
                }
                if (node.getStartTime() != operation.getReleaseTime()) {
                    throw new IllegalStateException("not expecting to arrive here");
                }
            }
        }
        if (operationNum + 2 != disjunctiveGraph.getNodes().size()) {
            throw new IllegalStateException("not expecting to arrive here, operationNum:" + operationNum + ",nodeNum" + (disjunctiveGraph.getNodes().size() + 2));
        }
    }

    /**
     * 将一个析取图转变为一个调度计划
     */
    public ScheduleResult convertGraphToSchedule(DisjunctiveGraph disjunctiveGraph){
        //首先，将析取图中的节点转变为operation对象
        List<Operation> operations=new ArrayList<>(disjunctiveGraph.getNodes().size());
        int order=0;
        for (int i = 1; i < disjunctiveGraph.getNodes().size()-1; i++) {
            DisjunctiveGraphNode node = disjunctiveGraph.getNodes().get(i);
            Operation operation = new Operation(node.getJobNum(), order, node.getOperationCode(), node.getStartTime(), node.getStartTime() + node.getProcessTime(), node.getMachineNum(), node.getProcessTime());
            operations.add(operation);
            if(node.getJobNum()!=disjunctiveGraph.getNodes().get(i+1).getJobNum()){
                order=0;
            }else{
                order++;
            }
        }
        //将工序根据作业号和机器号进行分组
        Map<Integer, List<Operation>> jobMap = operations.stream().collect(Collectors.groupingBy(Operation::getJobNumber));
        Map<Integer, List<Operation>> machineMap = operations.stream().collect(Collectors.groupingBy(Operation::getMachineNum));
        ArrayList<Machine> machines=new ArrayList<>();
        ArrayList<Job> jobs=new ArrayList<>();
        for (Map.Entry<Integer, List<Operation>> entry : jobMap.entrySet()) {
            ArrayList<Operation> value = new ArrayList<>(entry.getValue());
            value.sort(Comparator.comparingInt(Operation::getOrder));
            Job job = new Job(entry.getKey(), value);
            job.setCompleteTime(value.get(value.size()-1).getCompleteTime());
            jobs.add(job);
        }
        for (Map.Entry<Integer, List<Operation>> entry : machineMap.entrySet()) {
            ArrayList<Operation> value = new ArrayList<>(entry.getValue());
            value.sort(Comparator.comparingInt(Operation::getReleaseTime));
            Machine machine = new Machine(entry.getKey(), value);
            machine.setCompleteTime(value.get(value.size()-1).getCompleteTime());
            machines.add(machine);
        }
        return new ScheduleResult(machines,jobs,disjunctiveGraph.getMakespan());
    }

}
